#pragma once
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
#include <fstream>
#include <cassert>
#include "../Comm/Log.hpp"
#include "../Comm/Util.hpp"

namespace ns_model
{
    using namespace std;
    using namespace ns_util;
    using namespace ns_log;
    struct Question
    {
        std::string number; // 题目编号
        std::string title;   // 题目名称
        std::string star;   // 题目难度
        int cpu_limit;      // 时间限制
        int memo_limit;     // 空间限制

        std::string desc;   // 题目描述
        std::string header; // 预设置的代码段
        std::string tail;   // 测试用的代码段
    };

    const string questionList = "./questions/questions.list";
    const string questionpath = "./questions/";
    class Model
    {
    private:
        unordered_map<string, Question> questions;

    public:
        Model()
        {
            assert(LoadQuestionList(questionList));
        }
        ~Model()
        {
        }

        bool LoadQuestionList(const string &qlist)
        {
            ifstream in(qlist);
            if (!in.is_open())
            {
                LOG(FATAL) << "请检查是否存在题目列表文件\n";
                return false;
            }
            string line;
            while (getline(in, line))
            {
                vector<string> v;
                String_Util::SplitString(line, &v, " ");
                if (v.size() != 5)
                {
                    LOG(WARNING) << "部分题目加载失败，请检查题目列表文件的格式是否正确\n";
                    continue;
                }
                Question q;
                q.number = v[0];
                q.title = v[1];
                q.star = v[2];
                q.cpu_limit = stoi(v[3]);
                q.memo_limit = stoi(v[4]);

                string path = questionpath + q.number + "/";
                File_Util::ReadFile(path + "desc.txt", &(q.desc), true);
                File_Util::ReadFile(path + "header.cpp", &(q.header), true);
                File_Util::ReadFile(path + "tail.cpp", &(q.tail), true);

                questions[q.number] = q;
            }
            in.close();
            LOG(INFO) << "成功加载题库\n";
            return true;
        }

        bool GetAllQuestions(vector<Question> *out)
        {
            if (questions.size() == 0)
            {
                LOG(ERROR) << "获取题目失败\n";
                return false;
            }
            for (const auto &q : questions)
                out->emplace_back(q.second);
            return true;
        }
        
        bool GetOneQuestion(const string &number, Question *out)
        {
            const auto &it = questions.find(number);
            if (it == questions.end())
            {
                LOG(ERROR) << "获取题目失败，题目编号为" << number << "\n";
                return false;
            }
            *out = it->second;
            return true;
        }
    };
}
